
/*
 * Copyright (C) 2006-2015
 * 版权所有者为北京捷越联合信息咨询有限公司。本系统是商用软件,未经授权擅自复制或传播本程序的部分或全部将是非法的。
 * @title: RecCreditRefundPlanService.java
 * @package com.jy.modules.cims.recCreditRefundPlan.service
 * @author lizhenhuan
 * @date 2016-3-10 
 * @description: TODO受让债权还款计划和结算计划算法
 */
package com.jy.modules.cims.recCreditRefundPlan.service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.jy.modules.cims.common.CimsConstant;
import com.jy.modules.cims.common.exception.SysAssistException;
import com.jy.modules.cims.common.sysUtils.DateTimeUtils;
import com.jy.modules.cims.common.sysUtils.SimpleStringUtils;
import com.jy.modules.cims.component.credit.credit.ICreditFee;
import com.jy.modules.cims.data.common.dto.TCMmCostPlanDTO;
import com.jy.modules.cims.data.common.dto.TCMmCreditSettleParamDTO;
import com.jy.modules.cims.data.dao.RepaymentPlanDao;
import com.jy.modules.cims.data.dto.credit.CreditFeeDto;
import com.jy.modules.cims.data.dto.credit.CreditSettleParam;
import com.jy.modules.cims.data.dto.credit.RecCreditAlgorithmParam;
import com.jy.modules.cims.data.interact.core.credit.response.ResponseRepayPlanDTO;

@Service("com.jy.modules.cims.recCreditRefundPlan.service.RecCreditRefundPlanService")
public class RecCreditRefundPlanService {
	
	  private static final Logger logger = LoggerFactory.getLogger(RecCreditRefundPlanService.class);

	    /*
	     * 本地处理结算还款计划dao
	     */
	    @Autowired
	    private RepaymentPlanDao repaymentPlanDao;
	    
	    @Autowired
	    @Qualifier("com.jy.modules.cims.component.credit.credit.CreditFeeImpl")
	    private ICreditFee iCreditFee;
	
	// 受让结算还款计划开始
    public void beginRepaymentPlanToday(String dealCode) throws Exception {
        logger.info("受让还款计划和结算计划开始!");
        // 查询需要更新还款计划的债权
        List<CreditSettleParam> creditSettleParam = repaymentPlanDao.queryCreditDetailsRec(dealCode);
        
        int size = creditSettleParam.size();
        for (int i = 0; i < size && !creditSettleParam.isEmpty(); i++) {
            
             refoundRec(creditSettleParam.get(i));
          
        }
        logger.info("受让还款计划和结算计划结束!");
    }
    
    // 受让结算还款计划维护功能
    public void beginRepaymentPlanTransferId(String transferId) throws Exception {
        logger.info("受让还款计划和结算计划开始!");
        // 查询需要更新还款计划的债权
        List<CreditSettleParam> creditSettleParam = repaymentPlanDao.RecTransferIdPlans(transferId);
        
        int size = creditSettleParam.size();
        for (int i = 0; i < size && !creditSettleParam.isEmpty(); i++) {
            
             refoundRec(creditSettleParam.get(i));
          
        }
        logger.info("受让还款计划和结算计划结束!");
    }
    
    /**
     * 受让还款计划和结算计划生成
     * @param creditSettleParam 合约参数
     */
    private void refoundRec(CreditSettleParam creditSettleParam) throws Exception {
    	
    	
    	if (!SimpleStringUtils.hasText(creditSettleParam.getRepayment())) {
            throw new Exception("债权转让编号："+creditSettleParam.getTransferId()+"，未配置还款方式！结算计划生成失败！");
        }

    	if (!SimpleStringUtils.hasText(creditSettleParam.getmReplaceType())) {
            throw new Exception("债权转让编号："+creditSettleParam.getTransferId()+"，未配置月还处理方式！结算计划生成失败！");
        }

		boolean flag = true;//结算方式不支持
		String repayType = creditSettleParam.getRepayment();//结算还款方式
    	try {
			String creditCode = creditSettleParam.getCreditCode();//债权编号
			String transferId = creditSettleParam.getTransferId();//转让编号
			BigDecimal contractAmt = creditSettleParam.getContractAmt();//合同金额
			BigDecimal loanSum = creditSettleParam.getLoanSum();//放款金额
			int term = creditSettleParam.getTerm();//总期数
			int surplusTerm = creditSettleParam.getSurplusTerm();//剩余期数
			Date repayStartDate = creditSettleParam.getRepayStartDate();//起始还款日期
			BigDecimal rate = creditSettleParam.getRate();//合约月利率
			BigDecimal monthlyRate = creditSettleParam.getMonthlyRate();//产品月利率
			
			Calendar  cal = Calendar.getInstance();
			cal.setTime(repayStartDate);
			Date date = cal.getTime();
			
			Map<String, Object> paramMap = new HashMap<String, Object>();
			paramMap.put("creditcode", creditCode);
			paramMap.put("transferid", transferId);
			int priod = 1;
			List<ResponseRepayPlanDTO> planDataList = new ArrayList<ResponseRepayPlanDTO>();
			List<Map<String, Object>> planList = new ArrayList<Map<String, Object>>();
			
			//zhoupeng 还款方式变为三种
			//if(CimsConstant.DYD_REFUND_TYPE_DEBX.equals(repayType)||CimsConstant.DYD_REFUND_TYPE_FDDEBX.equals(repayType)||CimsConstant.DYD_REFUND_TYPE_CDDEBX.equals(repayType)){
			if(CimsConstant.DYD_REFUND_TYPE_DEBX.equals(repayType)){
				RecCreditAlgorithmParam recCreditAlgorithmParam = new RecCreditAlgorithmParam();
				
				recCreditAlgorithmParam.setCal(cal);
				recCreditAlgorithmParam.setContractAmt(contractAmt);
				recCreditAlgorithmParam.setCreditSettleParam(creditSettleParam);
				recCreditAlgorithmParam.setDate(date);
				recCreditAlgorithmParam.setLoanSum(loanSum);
				recCreditAlgorithmParam.setMonthlyRate(monthlyRate);
				recCreditAlgorithmParam.setPriod(priod);
				recCreditAlgorithmParam.setRate(rate);
				recCreditAlgorithmParam.setSurplusTerm(surplusTerm);
				recCreditAlgorithmParam.setTerm(term);
				
				recAverage(recCreditAlgorithmParam,planDataList,planList);
				//入库
				renInsertData(paramMap, planDataList, planList);
				
				recCreditAlgorithmParam = null;
				
			//}else if(CimsConstant.DYD_REFUND_TYPE_FDXXHB.equals(repayType)){ zhoupeng 还款方式变为三种
			}else if(CimsConstant.DYD_REFUND_TYPE_XXHB.equals(repayType) && CimsConstant.PRODUCT_TYPE_HOUSE.equals(creditSettleParam.getProductType())){
				RecCreditAlgorithmParam recCreditAlgorithmParam = new RecCreditAlgorithmParam();
				
				recCreditAlgorithmParam.setCal(cal);
				recCreditAlgorithmParam.setContractAmt(contractAmt);
				recCreditAlgorithmParam.setCreditSettleParam(creditSettleParam);
				recCreditAlgorithmParam.setDate(date);
				recCreditAlgorithmParam.setLoanSum(loanSum);
				recCreditAlgorithmParam.setMonthlyRate(monthlyRate);
				recCreditAlgorithmParam.setPriod(priod);
				recCreditAlgorithmParam.setRate(rate);
				recCreditAlgorithmParam.setSurplusTerm(surplusTerm);
				recCreditAlgorithmParam.setTerm(term);
				
				recHousingLoanFirstRateEndAccrual(recCreditAlgorithmParam,planDataList,planList);
				
				//入库
				renInsertData(paramMap, planDataList, planList);
				
				recCreditAlgorithmParam = null;
				
			//}else if(CimsConstant.DYD_REFUND_TYPE_FDXXHB2.equals(repayType)){								
			}else if(CimsConstant.DYD_REFUND_TYPE_XXHB2.equals(repayType)){
				RecCreditAlgorithmParam recCreditAlgorithmParam = new RecCreditAlgorithmParam();
				
				recCreditAlgorithmParam.setCal(cal);
				recCreditAlgorithmParam.setContractAmt(contractAmt);
				recCreditAlgorithmParam.setCreditSettleParam(creditSettleParam);
				recCreditAlgorithmParam.setDate(date);
				recCreditAlgorithmParam.setLoanSum(loanSum);
				recCreditAlgorithmParam.setMonthlyRate(monthlyRate);
				recCreditAlgorithmParam.setPriod(priod);
				recCreditAlgorithmParam.setRate(rate);
				recCreditAlgorithmParam.setSurplusTerm(surplusTerm);
				recCreditAlgorithmParam.setTerm(term);
				
				recHousingLoanFirstRateEndAccrualSecond(recCreditAlgorithmParam,planDataList,planList);
				
				//入库
				renInsertData(paramMap, planDataList, planList);
				
				recCreditAlgorithmParam = null;
			}else if(CimsConstant.DYD_REFUND_TYPE_XXHB.equals(repayType) && CimsConstant.PRODUCT_TYPE_CAR.equals(creditSettleParam.getProductType())){
				
				RecCreditAlgorithmParam recCreditAlgorithmParam = new RecCreditAlgorithmParam();
				
				recCreditAlgorithmParam.setCal(cal);
				recCreditAlgorithmParam.setContractAmt(contractAmt);
				recCreditAlgorithmParam.setCreditSettleParam(creditSettleParam);
				recCreditAlgorithmParam.setDate(date);
				recCreditAlgorithmParam.setLoanSum(loanSum);
				recCreditAlgorithmParam.setMonthlyRate(monthlyRate);
				recCreditAlgorithmParam.setPriod(priod);
				recCreditAlgorithmParam.setRate(rate);
				recCreditAlgorithmParam.setSurplusTerm(surplusTerm);
				recCreditAlgorithmParam.setTerm(term);
				
				recFirstRateEndAccrual(recCreditAlgorithmParam,planDataList,planList);
				//入库
				renInsertData(paramMap, planDataList, planList);
				
				recCreditAlgorithmParam = null;
			}else{
				flag = false;
				throw new Exception("结算方式不支持");
	        }
		} catch (Exception e) {
            logger.info("转让编号：" + creditSettleParam.getTransferId() + "----" + "债权编号：" + creditSettleParam.getCreditCode() + "生成还款计划和结算计划失败！" + e.getMessage());
            if(!flag){
            	throw new SysAssistException("转让编号：" + creditSettleParam.getTransferId() + "----" + "债权编号：" + creditSettleParam.getCreditCode() + "生成还款计划和结算计划失败！" + "原因：不正确的结算类型---" + repayType);
            }else{
            	throw new SysAssistException("转让编号：" + creditSettleParam.getTransferId() + "----" + "债权编号：" + creditSettleParam.getCreditCode() + "生成还款计划和结算计划失败！"+e.getMessage());
            }
		}
	}
    
    /**
     *  等额本息算法
     * @param recCreditAlgorithmParam 算法参数
     * @param planDataList 还款计划数据
     * @param planList结算计划数据
     */
    private void recAverage(RecCreditAlgorithmParam recCreditAlgorithmParam,List<ResponseRepayPlanDTO> planDataList,List<Map<String, Object>> planList){
    	
    	Date date = recCreditAlgorithmParam.getDate();
    	int term = recCreditAlgorithmParam.getTerm();
    	int surplusTerm = term;
    	int priod = recCreditAlgorithmParam.getPriod();
    	BigDecimal rate = recCreditAlgorithmParam.getRate();
    	BigDecimal monthlyRate = recCreditAlgorithmParam.getMonthlyRate();
    	BigDecimal contractAmt = recCreditAlgorithmParam.getContractAmt();
    	CreditSettleParam creditSettleParam = recCreditAlgorithmParam.getCreditSettleParam();
    	
    	Calendar refundCal = Calendar.getInstance();
		refundCal.setTime(date);
		Calendar settleCal = Calendar.getInstance();
		settleCal.setTime(date);
		
		//总期数
    	for(int i=1;i<=term;i++){
			//初始化参数
			double ratePram =  Math.pow(1+monthlyRate.doubleValue(), term);
			//月还金额
			BigDecimal thisRepaySum =contractAmt.multiply(monthlyRate).multiply(new BigDecimal(ratePram)).divide(new BigDecimal(ratePram-1),12,RoundingMode.HALF_UP);
			thisRepaySum = thisRepaySum.setScale(2,   BigDecimal.ROUND_HALF_UP);
			
			//参数初始化
			double ratePramCount =  Math.pow(1+monthlyRate.doubleValue(), surplusTerm);
			//剩余本金
			BigDecimal surAmount = thisRepaySum.divide(monthlyRate,12,RoundingMode.HALF_UP).multiply(new BigDecimal(1).subtract(new BigDecimal(1).divide(new BigDecimal(ratePramCount),12,RoundingMode.HALF_UP)));
			surAmount = surAmount.setScale(2, BigDecimal.ROUND_HALF_UP); 
			
			//应还息
			BigDecimal mustAccrual = surAmount.multiply(monthlyRate);
			mustAccrual = mustAccrual.setScale(2, BigDecimal.ROUND_HALF_UP); 
			
			//应还本
			BigDecimal mustAmount = thisRepaySum.subtract(mustAccrual);
			
			//还款计划
			recRefund(thisRepaySum, mustAmount, mustAccrual, priod, creditSettleParam, refundCal, planDataList);
			
			//结算计划
			if(null == creditSettleParam.getMonthlyRate()){
				monthlyRate = rate;
			}
			
			//初始化参数
			double ratePramSettle =  Math.pow(1+monthlyRate.doubleValue(), term);
			//月还金额
			BigDecimal thisRepaySumSettle =contractAmt.multiply(monthlyRate).multiply(new BigDecimal(ratePramSettle)).divide(new BigDecimal(ratePramSettle-1),12,RoundingMode.HALF_UP);
			thisRepaySumSettle = thisRepaySumSettle.setScale(2, BigDecimal.ROUND_HALF_UP); 
			
			//参数初始化
			double ratePramCountSettle =  Math.pow(1+monthlyRate.doubleValue(), surplusTerm);
			//剩余本金
			BigDecimal surAmountSettle = thisRepaySumSettle.divide(monthlyRate,12,RoundingMode.HALF_UP).multiply(new BigDecimal(1).subtract(new BigDecimal(1).divide(new BigDecimal(ratePramCountSettle),12,RoundingMode.HALF_UP)));
			surAmountSettle = surAmountSettle.setScale(2, BigDecimal.ROUND_HALF_UP); 
			
			//应还息
			BigDecimal mustAccrualSettle = surAmountSettle.multiply(monthlyRate);
			mustAccrualSettle = mustAccrualSettle.setScale(2, BigDecimal.ROUND_HALF_UP); 
			
			//应还本
			BigDecimal mustAmountSettle = thisRepaySumSettle.subtract(mustAccrualSettle);
			
			recSettle(thisRepaySumSettle, mustAmountSettle, mustAccrualSettle, priod, creditSettleParam, settleCal,planList);
			
			priod++;
			surplusTerm--;    	  
		}
    	
    }
    
    /**
     *  房贷先息后本
     * @param recCreditAlgorithmParam 算法参数
     * @param planDataList 还款计划数据
     * @param planList结算计划数据
     */
 private void recHousingLoanFirstRateEndAccrual(RecCreditAlgorithmParam recCreditAlgorithmParam,List<ResponseRepayPlanDTO> planDataList,List<Map<String, Object>> planList){
    	
	 	Date date = recCreditAlgorithmParam.getDate();
	 	int term = recCreditAlgorithmParam.getTerm();
	 	int priod = recCreditAlgorithmParam.getPriod();
	 	BigDecimal rate = recCreditAlgorithmParam.getRate();
	 	BigDecimal monthlyRate = recCreditAlgorithmParam.getMonthlyRate();
	 	BigDecimal contractAmt = recCreditAlgorithmParam.getContractAmt();
	 	CreditSettleParam creditSettleParam = recCreditAlgorithmParam.getCreditSettleParam();
	 
	 	//还款计划参数
	 	/**
		 * 非最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySum =contractAmt.multiply(monthlyRate);
		//应还息
		BigDecimal mustAccrual = thisRepaySum;
		//应还本
		BigDecimal mustAmount = BigDecimal.ZERO;
		
		/**
		 * 最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySumEnd =contractAmt.multiply(monthlyRate).add(contractAmt);
		//应还息
		BigDecimal mustAccrualEnd = contractAmt.multiply(monthlyRate);
		//应还本
		BigDecimal mustAmountEnd = contractAmt;
		
		//结算计划参数
		
		//结算计划
		if(null == creditSettleParam.getMonthlyRate()){
			monthlyRate = rate;
		}
		
		/**
		 * 非最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySumSettle =contractAmt.multiply(monthlyRate);
		//应还息
		BigDecimal mustAccrualSettle = thisRepaySumSettle;
		//应还本
		BigDecimal mustAmountSettle = BigDecimal.ZERO;
		
		/**
		 * 最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySumEndSettle =contractAmt.multiply(monthlyRate).add(contractAmt);
		//应还息
		BigDecimal mustAccrualEndSettle = contractAmt.multiply(monthlyRate);
		//应还本
		BigDecimal mustAmountEndSettle = contractAmt;
		
		Calendar refundCal = Calendar.getInstance();
		refundCal.setTime(date);
		Calendar settleCal = Calendar.getInstance();
		settleCal.setTime(date);
		for(int i=1;i<=term;i++){
			
			//最后一期
			if(i==term){
				recRefund(thisRepaySumEnd, mustAmountEnd, mustAccrualEnd, priod, creditSettleParam, refundCal, planDataList);
				
				recSettle(thisRepaySumEndSettle, mustAmountEndSettle, mustAccrualEndSettle, priod, creditSettleParam, settleCal, planList);
				
			}else{
				//非最后一期
				recRefund(thisRepaySum, mustAmount, mustAccrual, priod, creditSettleParam, refundCal,planDataList);
				
				recSettle(thisRepaySumSettle, mustAmountSettle, mustAccrualSettle, priod, creditSettleParam, settleCal,planList);
				
			}
			
			priod++;
		}
    	
    }
 
 /**
  *  房贷先息后本2
  * @param recCreditAlgorithmParam 算法参数
  * @param planDataList 还款计划数据
  * @param planList结算计划数据
  */
 private void recHousingLoanFirstRateEndAccrualSecond(RecCreditAlgorithmParam recCreditAlgorithmParam,List<ResponseRepayPlanDTO> planDataList,List<Map<String, Object>> planList){
 	
	 	Date date = recCreditAlgorithmParam.getDate();
	 	int term = recCreditAlgorithmParam.getTerm();
	 	int priod = recCreditAlgorithmParam.getPriod();
	 	BigDecimal rate = recCreditAlgorithmParam.getRate();
	 	BigDecimal monthlyRate = recCreditAlgorithmParam.getMonthlyRate();
	 	BigDecimal contractAmt = recCreditAlgorithmParam.getContractAmt();
	 	CreditSettleParam creditSettleParam = recCreditAlgorithmParam.getCreditSettleParam();
	 	//24期数
		if(term==CimsConstant.TERM_FIRST){
			/**
			 * 第一年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySum =contractAmt.multiply(monthlyRate);
			//应还息
			BigDecimal mustAccrual = thisRepaySum;
			//应还本
			BigDecimal mustAmount = BigDecimal.ZERO;
			
			/**
			 * 第一年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEnd = contractAmt.multiply(CimsConstant.FIRST_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEnd =contractAmt.multiply(monthlyRate).add(mustAmountEnd);
			//应还息
			BigDecimal mustAccrualEnd = contractAmt.multiply(monthlyRate);
			
			
			/**
			 * 第二年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumSecond =contractAmt.multiply(monthlyRate).multiply(CimsConstant.SECOND_YEAR_PARAM);
			//应还息
			BigDecimal mustAccrualSecond = thisRepaySumSecond;
			//应还本
			BigDecimal mustAmountSecond = BigDecimal.ZERO;
			
			/**
			 * 第二年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndSecond = contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndSecond =contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate).add(mustAmountEndSecond);
			//应还息
			BigDecimal mustAccrualEndSecond = contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate);
			
			//结算参数
			
			//结算计划
			if(null == creditSettleParam.getMonthlyRate()){
				monthlyRate = rate;
			}
			
			/**
			 * 第一年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumSettle =contractAmt.multiply(monthlyRate);
			//应还息
			BigDecimal mustAccrualSettle = thisRepaySumSettle;
			//应还本
			BigDecimal mustAmountSettle = BigDecimal.ZERO;
			
			/**
			 * 第一年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndSettle = contractAmt.multiply(CimsConstant.FIRST_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndSettle =contractAmt.multiply(monthlyRate).add(mustAmountEndSettle);
			//应还息
			BigDecimal mustAccrualEndSettle = contractAmt.multiply(monthlyRate);
			
			
			/**
			 * 第二年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumSecondSettle =contractAmt.multiply(monthlyRate).multiply(CimsConstant.SECOND_YEAR_PARAM);
			//应还息
			BigDecimal mustAccrualSecondSettle = thisRepaySumSecondSettle;
			//应还本
			BigDecimal mustAmountSecondSettle = BigDecimal.ZERO;
			
			/**
			 * 第二年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndSecondSettle = contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndSecondSettle =contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate).add(mustAmountEndSecondSettle);
			//应还息
			BigDecimal mustAccrualEndSecondSettle = contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate);
			
			Calendar refundCal = Calendar.getInstance();
			refundCal.setTime(date);
			Calendar settleCal = Calendar.getInstance();
			settleCal.setTime(date);
			for(int i=1;i<=term;i++){
				
				//第一年
				if(i<=term/2){
					if(i==term/2){
						recRefund(thisRepaySumEnd, mustAmountEnd, mustAccrualEnd, priod, creditSettleParam, refundCal,planDataList);
						
						recSettle(thisRepaySumEndSettle, mustAmountEndSettle, mustAccrualEndSettle, priod, creditSettleParam, settleCal,planList);
					}else{
						recRefund(thisRepaySum, mustAmount, mustAccrual, priod, creditSettleParam, refundCal,planDataList);
						
						recSettle(thisRepaySumSettle, mustAmountSettle, mustAccrualSettle, priod, creditSettleParam, settleCal,planList);
					}
				//第二年	
				}else if(i>term/2 && i<=term){
					if(i==term){
						recRefund(thisRepaySumEndSecond, mustAmountEndSecond, mustAccrualEndSecond, priod, creditSettleParam, refundCal,planDataList);
						
						recSettle(thisRepaySumEndSecondSettle, mustAmountEndSecondSettle, mustAccrualEndSecondSettle, priod, creditSettleParam, settleCal,planList);
					}else{
						recRefund(thisRepaySumSecond, mustAmountSecond, mustAccrualSecond, priod, creditSettleParam, refundCal,planDataList);
						
						recSettle(thisRepaySumSecondSettle, mustAmountSecondSettle, mustAccrualSecondSettle, priod, creditSettleParam, settleCal,planList);
					}
						
				}
				priod++;				
			}
		//36期数
		}else if(term==CimsConstant.TERM_SECOND){
			/**
			 * 第一年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySum =contractAmt.multiply(monthlyRate);
			//应还息
			BigDecimal mustAccrual = thisRepaySum;
			//应还本
			BigDecimal mustAmount = BigDecimal.ZERO;
			
			/**
			 * 第一年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEnd = contractAmt.multiply(CimsConstant.FIRST_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEnd =contractAmt.multiply(monthlyRate).add(mustAmountEnd);
			//应还息
			BigDecimal mustAccrualEnd = contractAmt.multiply(monthlyRate);
			
			
			/**
			 * 第二年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumSecond =contractAmt.multiply(monthlyRate).multiply(CimsConstant.SECOND_YEAR_PARAM);
			//应还息
			BigDecimal mustAccrualSecond = thisRepaySumSecond;
			//应还本
			BigDecimal mustAmountSecond = BigDecimal.ZERO;
			
			/**
			 * 第二年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndSecond = contractAmt.multiply(CimsConstant.FIRST_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndSecond =contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate).add(mustAmountEndSecond);
			//应还息
			BigDecimal mustAccrualEndSecond = contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate);
			
			/**
			 * 第三年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumThird =contractAmt.multiply(monthlyRate).multiply(CimsConstant.THIRD_YEAR_PARAM);
			//应还息
			BigDecimal mustAccrualThird = thisRepaySumThird;
			//应还本
			BigDecimal mustAmountThird = BigDecimal.ZERO;
			
			/**
			 * 第三年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndThird = contractAmt.multiply(CimsConstant.THIRD_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndThird =contractAmt.multiply(CimsConstant.THIRD_YEAR_PARAM).multiply(monthlyRate).add(mustAmountEndThird);
			//应还息
			BigDecimal mustAccrualEndThird = contractAmt.multiply(CimsConstant.THIRD_YEAR_PARAM).multiply(monthlyRate);
			
			//结算计划参数
			
			if(null == creditSettleParam.getMonthlyRate()){
				monthlyRate = rate;
			}
			
			/**
			 * 第一年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumSettle =contractAmt.multiply(monthlyRate);
			//应还息
			BigDecimal mustAccrualSettle = thisRepaySumSettle;
			//应还本
			BigDecimal mustAmountSettle = BigDecimal.ZERO;
			
			/**
			 * 第一年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndSettle = contractAmt.multiply(CimsConstant.FIRST_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndSettle =contractAmt.multiply(monthlyRate).add(mustAmountEndSettle);
			//应还息
			BigDecimal mustAccrualEndSettle = contractAmt.multiply(monthlyRate);
			
			
			/**
			 * 第二年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumSecondSettle =contractAmt.multiply(monthlyRate).multiply(CimsConstant.SECOND_YEAR_PARAM);
			//应还息
			BigDecimal mustAccrualSecondSettle = thisRepaySumSecondSettle;
			//应还本
			BigDecimal mustAmountSecondSettle = BigDecimal.ZERO;
			
			/**
			 * 第二年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndSecondSettle = contractAmt.multiply(CimsConstant.FIRST_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndSecondSettle =contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate).add(mustAmountEndSecondSettle);
			//应还息
			BigDecimal mustAccrualEndSecondSettle = contractAmt.multiply(CimsConstant.SECOND_YEAR_PARAM).multiply(monthlyRate);
			
			/**
			 * 第三年非最后一个月
			 */
			
			//月还金额
			BigDecimal thisRepaySumThirdSettle =contractAmt.multiply(monthlyRate).multiply(CimsConstant.THIRD_YEAR_PARAM);
			//应还息
			BigDecimal mustAccrualThirdSettle = thisRepaySumThirdSettle;
			//应还本
			BigDecimal mustAmountThirdSettle = BigDecimal.ZERO;
			
			/**
			 * 第三年最后一个月
			 */
			//应还本
			BigDecimal mustAmountEndThirdSettle = contractAmt.multiply(CimsConstant.THIRD_YEAR_PARAM);
			//月还金额
			BigDecimal thisRepaySumEndThirdSettle =contractAmt.multiply(CimsConstant.THIRD_YEAR_PARAM).multiply(monthlyRate).add(mustAmountEndThirdSettle);
			//应还息
			BigDecimal mustAccrualEndThirdSettle = contractAmt.multiply(CimsConstant.THIRD_YEAR_PARAM).multiply(monthlyRate);
			
			Calendar refundCal = Calendar.getInstance();
			refundCal.setTime(date);
			Calendar settleCal = Calendar.getInstance();
			settleCal.setTime(date);
			for(int i=1;i<=term;i++){
				
					//第一年
					if(i<=term/3){
						if(i==term/3){
							recRefund(thisRepaySumEnd, mustAmountEnd, mustAccrualEnd, priod, creditSettleParam, refundCal,planDataList);
							
							recSettle(thisRepaySumEndSettle, mustAmountEndSettle, mustAccrualEndSettle, priod, creditSettleParam, settleCal,planList);
						}else{
							recRefund(thisRepaySum, mustAmount, mustAccrual, priod, creditSettleParam, refundCal,planDataList);
							
							recSettle(thisRepaySumSettle, mustAmountSettle, mustAccrualSettle, priod, creditSettleParam, settleCal,planList);
						}
					//第二年	
					}else if(i>term/3 && i<=(term/3)*2){
						if(i==(term/3)*2){
							recRefund(thisRepaySumEndSecond, mustAmountEndSecond, mustAccrualEndSecond, priod, creditSettleParam, refundCal,planDataList);
							
							recSettle(thisRepaySumEndSecondSettle, mustAmountEndSecondSettle, mustAccrualEndSecondSettle, priod, creditSettleParam, settleCal,planList);
						}else{
							recRefund(thisRepaySumSecond, mustAmountSecond, mustAccrualSecond, priod, creditSettleParam, refundCal,planDataList);
							
							recSettle(thisRepaySumSecondSettle, mustAmountSecondSettle, mustAccrualSecondSettle, priod, creditSettleParam, settleCal,planList);
						}
							
					//第三年
					}else if(i>(term/3)*2 && i<=term){
						if(i==term){
							recRefund(thisRepaySumEndThird, mustAmountEndThird, mustAccrualEndThird, priod, creditSettleParam, refundCal,planDataList);
						
							recSettle(thisRepaySumEndThirdSettle, mustAmountEndThirdSettle, mustAccrualEndThirdSettle, priod, creditSettleParam, settleCal,planList);
						}else{
							recRefund(thisRepaySumThird, mustAmountThird, mustAccrualThird, priod, creditSettleParam, refundCal,planDataList);
						
							recSettle(thisRepaySumThirdSettle, mustAmountThirdSettle, mustAccrualThirdSettle, priod, creditSettleParam, settleCal,planList);
						}
							
					}
					priod++;				
			}
		}else{
			throw new SysAssistException("房贷部分先息后本仅支持24期和36期，期数为：" + term + ",不支持此期数！");
		}
 	
 }
 
 /**
  *  先息后本
  * @param recCreditAlgorithmParam 算法参数
  * @param planDataList 还款计划数据
  * @param planList结算计划数据
  */
 private void recFirstRateEndAccrual(RecCreditAlgorithmParam recCreditAlgorithmParam,List<ResponseRepayPlanDTO> planDataList,List<Map<String, Object>> planList){
 	
	 	Date date = recCreditAlgorithmParam.getDate();
	 	int term = recCreditAlgorithmParam.getTerm();
	 	int priod = recCreditAlgorithmParam.getPriod();
	 	BigDecimal rate = recCreditAlgorithmParam.getRate();
	 	BigDecimal monthlyRate = recCreditAlgorithmParam.getMonthlyRate();
	 	BigDecimal loanSum = recCreditAlgorithmParam.getLoanSum();
	 	CreditSettleParam creditSettleParam = recCreditAlgorithmParam.getCreditSettleParam();
	 /**
		 * 非最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySum =loanSum.multiply(monthlyRate);
		//应还息
		BigDecimal mustAccrual = thisRepaySum;
		//应还本
		BigDecimal mustAmount = BigDecimal.ZERO;
		
		/**
		 * 最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySumEnd =loanSum.multiply(monthlyRate).add(loanSum);
		//应还息
		BigDecimal mustAccrualEnd = loanSum.multiply(monthlyRate);
		//应还本
		BigDecimal mustAmountEnd = loanSum;
		
		//结算计划参数
		
		if(null == creditSettleParam.getMonthlyRate()){
			monthlyRate = rate;
		}
		
		/**
		 * 非最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySumSettle =loanSum.multiply(monthlyRate);
		//应还息
		BigDecimal mustAccrualSettle = thisRepaySumSettle;
		//应还本
		BigDecimal mustAmountSettle = BigDecimal.ZERO;
		
		/**
		 * 最后一个月
		 */
		//月还金额
		BigDecimal thisRepaySumEndSettle =loanSum.multiply(monthlyRate).add(loanSum);
		//应还息
		BigDecimal mustAccrualEndSettle = loanSum.multiply(monthlyRate);
		//应还本
		BigDecimal mustAmountEndSettle = loanSum;
	 
		Calendar refundCal = Calendar.getInstance();
		refundCal.setTime(date);
		Calendar settleCal = Calendar.getInstance();
		settleCal.setTime(date);
		for(int i=1;i<=term;i++){
			
			//最后一期
			if(i==term){
				recRefund(thisRepaySumEnd, mustAmountEnd, mustAccrualEnd, priod, creditSettleParam, refundCal,planDataList);
				
				recSettle(thisRepaySumEndSettle, mustAmountEndSettle, mustAccrualEndSettle, priod, creditSettleParam, settleCal,planList);
				
			}else{
				//非最后一期
				recRefund(thisRepaySum, mustAmount, mustAccrual, priod, creditSettleParam, refundCal,planDataList);
			
				recSettle(thisRepaySumSettle, mustAmountSettle, mustAccrualSettle, priod, creditSettleParam, settleCal,planList);
				
			}
			
			priod++;
		}
 	
 }
	 /**
	  * 还款计划数据
	  * @param thisRepaySum 月还金额
	  * @param mustAmount 应还本
	  * @param mustAccrual 应还息
	  * @param priod 期数
	  * @param creditSettleParam 合约参数
	  * @param cal 当期日期
	  * @param i 计数
	  * @param planDataList 还款计划数据
	  */
    private void recRefund(BigDecimal thisRepaySum,BigDecimal mustAmount,BigDecimal mustAccrual,int priod,CreditSettleParam creditSettleParam,Calendar cal,List<ResponseRepayPlanDTO> planDataList) {
    	//还款计划开始
		ResponseRepayPlanDTO responseRepayPlanDTO = new ResponseRepayPlanDTO();
		responseRepayPlanDTO.setCurPeriod(priod);
		responseRepayPlanDTO.setCreditCode(creditSettleParam.getCreditCode());
		responseRepayPlanDTO.setTransferId(creditSettleParam.getTransferId());
		responseRepayPlanDTO.setRepayPanelty(new BigDecimal(0));
		responseRepayPlanDTO.setRepayDefault(new BigDecimal(0));
		responseRepayPlanDTO.setValidateState(1);
		responseRepayPlanDTO.setCurRepayMoney(thisRepaySum);
		responseRepayPlanDTO.setCurRepayBase(mustAmount);
		responseRepayPlanDTO.setCurRepayInst(mustAccrual);
		
		cal.setTime(cal.getTime());
		if(priod>1){
			cal.add(Calendar.MONTH, 1);
		}
	
	    int day = Integer.parseInt(creditSettleParam.getBillDate());
	    cal.set(Calendar.DAY_OF_MONTH, day);
	    
		responseRepayPlanDTO.setCurRepayDate(DateTimeUtils.formatDate(cal.getTime(), DateTimeUtils.DEFAULT_DATE_TIME_FORMAT));
		planDataList.add(responseRepayPlanDTO);
		responseRepayPlanDTO = null;
	}
    
    /**
	  * 结算计划数据
	  * @param thisRepaySum 月还金额
	  * @param mustAmount 应还本
	  * @param mustAccrual 应还息
	  * @param priod 期数
	  * @param creditSettleParam 合约参数
	  * @param cal 当期日期
	  * @param i 计数
	  * @param planList 结算计划数据
	  */
    private void recSettle(BigDecimal thisRepaySum,BigDecimal mustAmount,BigDecimal mustAccrual,int priod,CreditSettleParam creditSettleParam,Calendar cal,List<Map<String, Object>> planList) {
    	
		cal.setTime(cal.getTime());
		if(priod>1){
			cal.add(Calendar.MONTH, 1);
		}
	    int day = Integer.parseInt(creditSettleParam.getBillDate());
	    cal.set(Calendar.DAY_OF_MONTH, day);

		//结算计划开始
		Map<String, Object> map = new HashMap<String, Object>();
		TCMmCreditSettleParamDTO tCMmCreditSettleParamDTO = new TCMmCreditSettleParamDTO();
        tCMmCreditSettleParamDTO.setReplaceType(creditSettleParam.getmReplaceType());
        TCMmCostPlanDTO tCMmCostPlanDTO = new TCMmCostPlanDTO();
        tCMmCostPlanDTO.setMustAmount(mustAmount);// 应还本
        tCMmCostPlanDTO.setMustAccrual(mustAccrual);// 应还息
		CreditFeeDto creditFeeDto = iCreditFee.getSettleInfo(tCMmCreditSettleParamDTO, tCMmCostPlanDTO);
		map.put("term", priod);
        map.put("must_amount", mustAmount);
        map.put("must_accrual", mustAccrual);
        map.put("this_repay_sum", thisRepaySum);
        map.put("credit_code", creditSettleParam.getCreditCode());
        map.put("transfer_id", creditSettleParam.getTransferId());
        map.put("start_date", DateTimeUtils.formatDate(cal.getTime(), DateTimeUtils.DEFAULT_DATE_TIME_FORMAT));
        map.put("validate_state", "1");
        map.put("match_amount", creditFeeDto.getMatchAmount());
        map.put("return_amount", creditFeeDto.getReturnAmount());
        planList.add(map);
        tCMmCostPlanDTO=null;
	}
    
    /**
     * 入库操作
     * @param paramMap
     * @param planDataList
     * @param planList
     */
    private void renInsertData(Map<String, Object> paramMap,List<ResponseRepayPlanDTO> planDataList,List<Map<String, Object>> planList){
    	
    	try {
			//插入还款计划
			int cc = repaymentPlanDao.selectCountLoanPlans(paramMap);
			if(planDataList.size()>0 && cc==0){
				repaymentPlanDao.insertPlanListDYD(planDataList);
			}
		} catch (Exception e) {
			throw new SysAssistException("插入还款计划失败" +e.getMessage());
		}
				
		try {
			//插入结算计划
			int sumNo = repaymentPlanDao.selectCountSettlePlans(paramMap);
			if (planList.size()>0 && sumNo == 0) {
				repaymentPlanDao.initSettlePlan(planList);
			}
		} catch (Exception e) {
			throw new SysAssistException("插入结算计划失败"  + e.getMessage());
		}
    }
    
}
